<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Common\Dao;

use App\Model\Model;

/**
 * Class BaseDao.
 */
abstract class BaseDao
{
    public function getMyModel()
    {
        return $this->getModel();
    }

    /**
     * @return string
     */
    public function getPk()
    {
        return ($this->getModel())->getKeyName();
    }

    /**
     * @return bool
     */
    public function exists(int $id)
    {
        return $this->fieldExists($this->getPk(), $id);
    }

    public function fieldExists($field, $value, ?int $except = null): bool
    {
        $query = ($this->getModel())::where($field, $value);
        if (! is_null($except)) {
            $query->where($this->getPk(), '<>', $except);
        }
        return $query->count() > 0;
    }

    /**
     * @return Model|self
     */
    public function create(array $data)
    {
        return ($this->getModel())::create($data);
    }

    /**
     * @return int|string
     */
    public function insertGetId(array $data)
    {
        return ($this->getModel())::insertGetId($data);
    }

    /**
     * @return int
     */
    public function update(int $id, array $data)
    {
        return ($this->getModel())::where($this->getPk(), $id)->update($data);
    }

    /**
     * @return int
     */
    public function updates(array $ids, array $data)
    {
        return ($this->getModel())::whereIn($this->getPk(), $ids)->update($data);
    }

    /**
     * @return int
     */
    public function delete(int $id)
    {
        return ($this->getModel())::where($this->getPk(), $id)->delete();
    }

    /**
     * @param int $id
     * @return null|array|Model
     */
    public function get($id)
    {
        return ($this->getModel())::find($id);
    }

    /**
     * @return null|array|Model
     */
    public function getWhere(array $where, array $field = ['*'], array $with = [])
    {
        return ($this->getModel())->where($where)->when($with, function ($query) use ($with) {
            $query->with($with);
        })->select($field)->first();
    }

    public function selectWhere(array $where, array $field = ['*'])
    {
        return ($this->getModel())::where($where)->select($field)->get();
    }

    /**
     * @param array $with
     * @param array $where
     * @param mixed $value
     */
    public function selectWhereWith(string $whereField, string $op, $value, array $field = ['*'], $with = [], $where = [])
    {
        return ($this->getModel())::with($with)->where($whereField, $op, $value)->where($where)->select($field)->get();
    }

    /**
     * @param array $with
     * @return null|array|Model
     */
    public function getWith(int $id, $with = [])
    {
        return ($this->getModel())::with($with)->find($id);
    }

    /**
     * @return int
     */
    public function insertAll(array $data)
    {
        return ($this->getModel())::insert($data);
    }

    /**
     * TODO 通过条件判断是否存在.
     */
    public function getWhereCount(array $where)
    {
        return $this->getModel()::where($where)->count();
    }

    public function existsWhere($where)
    {
        return ($this->getModel())::where($where)->count() > 0;
    }

    /**
     * TODO 查询,如果不存在就创建.
     * @return null|array|Model
     */
    public function findOrCreate(array $where)
    {
        $res = $this->getModel()::where($where)->first();
        if (! $res) {
            $res = $this->getModel()::create($where);
        }
        return $res;
    }

    /**
     * TODO 自增.
     */
    public function incField(int $id, string $field, $num = 1): int
    {
        return $this->getModel()::where($this->getPk(), $id)->increment($field, $num);
    }

    /**
     * TODO 自减.
     */
    public function decField(int $id, string $field, $num = 1): int
    {
        return $this->getModel()::where($this->getPk(), $id)
            ->where($field, '>=', $num)
            ->decrement($field, $num);
    }

    public function getValue(array $where, string $field)
    {
        return ($this->getModel())::where($where)->value($field);
    }

    public function getColumn(array $where, string $field)
    {
        return ($this->getModel())::where($where)->pluck($field)->toArray();
    }

    public function getInColumn(string $in, array $ids, string $field)
    {
        return ($this->getModel())::whereIn($in, $ids)->pluck($field)->toArray();
    }

    public function updateWhere(array $where, array $data): int
    {
        return ($this->getModel())::where($where)->update($data);
    }

    public function getFieldLikeFind(string $field, string $value)
    {
        return ($this->getModel())::where($field, 'like', '%' . $value . '%')->first();
    }

    /**
     * @return Model
     */
    abstract protected function getModel();
}
